/**
 *     工具 类
 */

import BaseUI from "../BaseUI";
import QuickList from "./QuickLIst";

export default class qrj_tools {

    /**
     *      关闭 调试 信息
     **/
    public static closeDebug() {
        cc.debug.setDisplayStats(false);
    }

    /***********************************************************
     *         日期 时间 处理
     ***********************************************************/
    ///////// 同步服务器 时间
    public static timeOffset: number = 0;
    public static setServerTime(time: number) {
        qrj_tools.timeOffset = time - new Date().getTime();
        cc.log("timeOffset:", qrj_tools.timeOffset)
    }
    public static getServerTime() {
        return new Date().getTime() + qrj_tools.timeOffset;
    }


    /**
     * 判断是否同一天
     * @param _time    时间戳
     */
    public static isCurrentDay(_time: number): boolean {
        let myDate = new Date(_time);
        let currentData = new Date();
        if (myDate.getFullYear() == currentData.getFullYear() &&
            myDate.getMonth() == currentData.getMonth() &&
            myDate.getDate() == currentData.getDate()) {
            return true;
        }
        return false;
    }

    /**
     * 获取当前时间戳
     */
    public static getCurrentTime(): number {
        return new Date().getTime();
    }

    /**
     *      判断 两个 时间戳 是否 是同一周
     * @param old
     * @param now 
     */
    public static isSameWeek(old: number, now: number): boolean {
        //cc.log("时间：："+this.getTIme(0)+":::"+this.getTIme(old)+":::"+this.getTIme(now));
        var oneDayTime = 1000 * 60 * 60 * 24;
        var old_count = Math.floor(old / oneDayTime);
        var now_other = Math.floor(now / oneDayTime);
        // cc.log("判断是否为桶一周::"+parseInt((old_count+3)/7)+":::"+parseInt((now_other+3)/7));
        return Math.floor((old_count + 3) / 7) == Math.floor((now_other + 3) / 7);
    }

    /**
     *    将时间戳 格式化成 年-月-日 时:分:秒
     */
    public static getTime(time: number): String {
        var date = new Date(time);
        let Y = date.getFullYear() + '-';
        let M = (date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1) + '-';
        let D = date.getDate() + ' ';
        let h = date.getHours() + ':';
        let m = date.getMinutes() + ':';
        let s = date.getSeconds();
        return (Y + M + D + h + m + s);
    }

    /**
     *     毫秒 转换格式 (秒:毫秒) 
     *     sn = 2 秒部分最低保留位数
     *     mn = 2 毫秒部分最低保留位数
     */
    public static ms_to_string(t: number, sn = 2, mn = 2, fh = ":") {
        let s = "" + Math.floor(t / 1000);
        while (s.length < sn) {
            s = "0" + s;
        }
        let ms = "" + Math.floor(t % 1000 / 10);
        while (ms.length < mn) {
            ms = "0" + ms;
        }
        return s + fh + ms;
    }

    /**
     *    秒 转换格式 (分:秒) 
     *      mn = 分 最低保留位数
     *      sn = 秒 最低保留位数
     */
    public static second_to_string(se: number, mn = 2, sn = 2, fh = ":") {
        let m = "" + Math.floor(se / 60);
        while (m.length < mn) {
            m = "0" + m;
        }
        let s = "" + se % 60;
        while (s.length < sn) {
            s = "0" + s;
        }
        return m + fh + s;
    }

    /**
     *    秒 转换格式 (时:分:秒) 
     *      mn = 分 最低保留位数
     *      sn = 秒 最低保留位数
     */
    public static second_to_string_2(se: number, hn = 2, mn = 2, sn = 2, fh = ":") {
        let h = "" + Math.floor(se / 3600);
        while (h.length < mn) {
            h = "0" + h;
        }
        let m = "" + Math.floor(se / 60);
        while (m.length < mn) {
            m = "0" + m;
        }
        let s = "" + se % 60;
        while (s.length < sn) {
            s = "0" + s;
        }
        return h + fh + m + fh + s;
    }

    public static getTimeStrByS(second: number) {
        second = Math.floor(second);
        if (second < 0) second = 0;
        var d = Math.floor(second / 3600 / 24);
        second -= d * 3600 * 24;
        var h = Math.floor(second / 3600);
        second -= h * 3600;
        var m = Math.floor(second / 60);
        second -= m * 60;
        var front = "00";
        if (h > 9) {
            front = "" + h;
        } else {
            front = "0" + h;
        }
        var mid = "00";
        if (m > 9) {
            mid = "" + m;
        } else {
            mid = "0" + m;
        }
        var back = "00";
        if (second > 9) {
            back = "" + second;
        } else {
            back = "0" + second;
        }

        if (d > 0) {
            return d + "天" + h + "时" + m + "分";
        }
        else {
            var longTime = h > 0;
            if (longTime) {
                return front + ":" + mid;
            } else {
                return mid + ":" + back;//+ '秒';
            }
        }
    }


    /**
     *      自定义 LOG 
     */
    public static log(out: any): void {
        switch (typeof (out)) {
            case "number":
                cc.log("TYPE:NUMBER  = " + out);
                break;
            case "string":
                cc.log("TYPE:STRING  >" + out + "<");
                break;
            case "boolean":
                cc.log("TYPE:BOOLEAN  = " + out);
                break;
            case "object":
                cc.log("TYPE:OBJECT  >" + JSON.stringify(out) + "<");
                break;
            case "function":
                cc.log("TYPE:FUNCTION  =", out);
                break;
            case "undefined":
                cc.log("TYPE:UNDEFINDED");
                break;
            default:
                break;
        }
    }


    public static obj_to_json(obj: any): string {
        return JSON.stringify(obj);
    }

    public static json_to_obj(json: string): any {
        return JSON.parse(json);
    }

    public static string_trim(str: string): string {
        return str.replace(/(^\s*)|(\s*$)/g, "");
    }



    /**
     *       文字提示
     *    pn = 父节点 (可选)
     */
    public static toast_1(str: string, color = cc.Color.BLACK, time = 2, pn: cc.Node = null) {
        let node = new cc.Node();
        let label = node.addComponent(cc.Label);
        label.string = str;
        label.fontSize = 40;

        let act_1 = cc.moveBy(time, 0, 80);
        let act_2 = cc.fadeOut(time);
        let act_3 = cc.callFunc(() => {
            node.removeFromParent();
        });
        node.runAction(cc.sequence(cc.spawn(act_1, act_2), act_3));

        if (pn != null) {
            node.x = 0;
            node.y = - pn.height / 2 + pn.height / 5;
            node.color = color;
            pn.addChild(node);
            return;
        }

        let scen = cc.director.getScene();
        let canvas = scen.getChildByName("Canvas");
        if (canvas == null) {
            cc.error("没有找到canvas");
            return;
        }
        node.x = canvas.width / 2;
        node.y = canvas.height / 5;
        node.color = color;
        scen.addChild(node);
    }

    public static toast(text: string, gravity = "CENTER", duration = 2, bg_color = cc.color(102, 102, 102, 200)) {
        // canvas
        let canvas = cc.director.getScene().getComponentInChildren(cc.Canvas);
        let width = canvas.node.width;
        let height = canvas.node.height;
        let bgNode = new cc.Node();
        // bgNode.group = "UI";

        // Lable文本格式设置
        let textNode = new cc.Node();
        let textLabel = textNode.addComponent(cc.Label);
        textLabel.horizontalAlign = cc.Label.HorizontalAlign.CENTER;
        textLabel.verticalAlign = cc.Label.VerticalAlign.CENTER;
        textLabel.fontSize = 30;
        textLabel.string = text;

        // 当文本宽度过长时，设置为自动换行格式
        if (text.length * textLabel.fontSize > (width * 3) / 5) {
            textNode.width = (width * 3) / 5;
            textLabel.overflow = cc.Label.Overflow.RESIZE_HEIGHT;
        } else {
            textNode.width = text.length * textLabel.fontSize;
        }
        let lineCount =
            ~~((text.length * textLabel.fontSize) / ((width * 3) / 5)) + 1;
        textNode.height = textLabel.fontSize * lineCount;

        // 背景设置
        let ctx = bgNode.addComponent(cc.Graphics);
        ctx.arc(
            -textNode.width / 2,
            0,
            textNode.height / 2 + 20,
            0.5 * Math.PI,
            1.5 * Math.PI,
            true
        );
        ctx.lineTo(textNode.width / 2, -(textNode.height / 2 + 20));
        ctx.arc(
            textNode.width / 2,
            0,
            textNode.height / 2 + 20,
            1.5 * Math.PI,
            0.5 * Math.PI,
            true
        );
        ctx.lineTo(-textNode.width / 2, textNode.height / 2 + 20);
        ctx.fillColor = bg_color;
        ctx.fill();

        bgNode.addChild(textNode);

        // gravity 设置Toast显示的位置
        if (gravity === "CENTER") {
            bgNode.y = 0;
            bgNode.x = 0;
        } else if (gravity === "TOP") {
            bgNode.y = bgNode.y + (height / 5) * 2;
        } else if (gravity === "BOTTOM") {
            bgNode.y = bgNode.y - (height / 5) * 2;
        }

        bgNode.zIndex = cc.macro.MAX_ZINDEX;
        canvas.node.addChild(bgNode);


        let finished = cc.callFunc(() => {
            bgNode.removeFromParent();
        });
        let action = cc.sequence(
            cc.moveBy(duration, cc.v2(0, 0)),
            cc.fadeOut(0.3),
            finished
        );
        bgNode.runAction(action);
    }


    public static set_pause(b: boolean) {
        if (b == true) {
            cc.director.getScheduler().setTimeScale(0.0000000000001);
            cc.log("暂停");
        } else {
            cc.director.getScheduler().setTimeScale(1);
            cc.log("恢复");
        }
    }

    /////////// 获得 URL 传递的参数
    public static getQueryString(name: string) {
        var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i");
        var r = window.location.search.substr(1).match(reg);
        if (r != null) return unescape(r[2]); return null;
    }


    ////////// 截短 昵称
    public static SliceNickname(str: string, n: number) {
        if (str && str.length > n) {
            return str.slice(0, n) + '...';
        } else {
            return str;
        }
    }


    public static save_localData(baseObj: object, nameString: string): void {
        var baseData = JSON.stringify(baseObj);
        cc.sys.localStorage.setItem(nameString, baseData);
    };

    public static load_localData(nameString: string): object {
        var baseDataa = cc.sys.localStorage.getItem(nameString); //从本地读取数据
        if (baseDataa == null || baseDataa == "") return null;
        return JSON.parse(baseDataa); //将string转换成json
    };

    ////////////// 判断 有效 URL
    public static isValidURL(url: string): boolean {
        const pattern = new RegExp(
            '^(https?:\\/\\/)?' + // protocol
            '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|' + // domain name and extension
            '((\\d{1,3}\\.){3}\\d{1,3}))' + // OR ip (v4) address
            '(\\:\\d+)?' + // port
            '(\\/[-a-z\\d%_.~+]*)*' + // path
            '(\\?[;&a-z\\d%_.~+=-]*)?' + // query string
            '(\\#[-a-z\\d_]*)?$', 'i' // fragment locator
        );
        return !!pattern.test(url);
    }

    /**
     *    base64 图片格式转换 (web,微信小游戏)
     */
    public static base64_to_sprFrame(res: string): Promise<cc.SpriteFrame> {
        return new Promise((resolve, reject) => {
            let r: cc.SpriteFrame = null;
            let img = new Image();
            img.onload = () => {
                let texture = new cc.Texture2D();
                texture.initWithElement(img);
                texture.handleLoadedTexture();
                r = new cc.SpriteFrame(texture);
                resolve(r);
            }
            img.src = res;
        });
    }

    /**
    *      文字滚动特效
    */
    public static set_number_label(lab: cc.Node | cc.Label, val: number, step = 0) {
        let c: cc.Label = null;
        if (lab instanceof cc.Label) {
            c = lab;
        } else {
            c = lab.getComponent(cc.Label)
            if (c == null) { return; }
        }
        let old = Number(c.string);

        c.unscheduleAllCallbacks();

        if (step == 0) {
            step = Math.floor((val - Number(c.string)) / 60);
            if (step == 0) {
                step = val > old ? 1 : -1;
            }
        }

        if (val > old) { ///// 增长
            let fun = function () {
                let old = Number(c.string);
                if (old + step >= val) {
                    c.string = val.toString();
                    c.unschedule(fun);
                } else {
                    c.string = (old + step).toString();
                }
            }
            c.schedule(fun, 0);
        } else {
            let fun = function () {
                let old = Number(c.string);
                if (old + step <= val) {
                    c.string = val.toString();
                    c.unschedule(fun);
                } else {
                    c.string = (old + step).toString();
                }
            }
        }
    }

    /**
     *    数据对象 内 所有 可以转换成数字的对象 , 转成数字
     */
    public static data_type_to_number(obj: object | any[]) {
        if (Array.isArray(obj) == true) {
            for (let i = 0; i < obj.length; i++) {
                if (!isNaN(Number(obj[i]))) {
                    obj[i] = Number(obj[i]);
                } else {
                    this.data_type_to_number(obj[i]);
                }
            }
        } else if (obj && typeof obj == "object") {
            for (let key in obj) {
                if (!isNaN(Number(obj[key]))) {
                    obj[key] = Number(obj[key]);
                } else {
                    this.data_type_to_number(obj[key]);
                }
            }
        }
    }


    ///////// webview 自定义内容  (WEB,原生平台有效)
    public static set_webview_code(wv: cc.WebView, code: string, backColor = "#ffffff") {
        let sc = `
            document.body.style.backgroundColor = "${backColor}";
            document.body.innerHTML="${code}"
        `;
        wv.evaluateJS(sc);
    }

    public static deepCopy_2(obj) {
        if (obj === null || typeof obj !== 'object') {
            // 基本类型或null，直接返回
            return obj;
        }

        let clone;

        if (obj instanceof Date) {
            // 日期对象
            clone = new Date(obj);
        } else if (obj instanceof RegExp) {
            // 正则表达式对象
            clone = new RegExp(obj);
        } else if (Array.isArray(obj)) {
            // 处理数组
            clone = [];
            for (let i = 0; i < obj.length; i++) {
                clone.push(this.deepCopy_2(obj[i]));
            }
        } else {
            // 处理普通对象
            clone = {};
            for (let key in obj) {
                if (obj.hasOwnProperty(key)) {
                    clone[key] = this.deepCopy_2(obj[key]);
                }
            }
        }

        return clone;
    }

    public static deepCopy<T>(obj: T): T {
        if (obj === null || typeof obj !== 'object') {
            // 如果不是复杂数据类型，直接返回
            return obj;
        }

        let copy: T;

        if (obj instanceof Date) {
            copy = new Date(obj.getTime()) as T;
        } else if (obj instanceof RegExp) {
            copy = new RegExp(obj) as T;
        } else {
            // 处理普通对象或数组
            copy = Object.assign({}, obj) as T;
            for (let key in obj) {
                if (obj.hasOwnProperty(key)) { // 确保拷贝的是实例上的属性，排除原型链上的属性
                    copy[key] = this.deepCopy(obj[key]); // 递归拷贝属性值
                }
            }
        }

        return copy;
    }


    public static base64encode(str) {
        var base64EncodeChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
        var out, i, len;
        var c1, c2, c3;
        len = str.length;
        i = 0;
        out = "";
        while (i < len) {
            c1 = str.charCodeAt(i++) & 0xff;
            if (i == len) {
                out += base64EncodeChars.charAt(c1 >> 2);
                out += base64EncodeChars.charAt((c1 & 0x3) << 4);
                out += "==";
                break;
            }
            c2 = str.charCodeAt(i++);
            if (i == len) {
                out += base64EncodeChars.charAt(c1 >> 2);
                out += base64EncodeChars.charAt(((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4));
                out += base64EncodeChars.charAt((c2 & 0xF) << 2);
                out += "=";
                break;
            }
            c3 = str.charCodeAt(i++);
            out += base64EncodeChars.charAt(c1 >> 2);
            out += base64EncodeChars.charAt(((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4));
            out += base64EncodeChars.charAt(((c2 & 0xF) << 2) | ((c3 & 0xC0) >> 6));
            out += base64EncodeChars.charAt(c3 & 0x3F);
        }
        return out;
    }

    public static base64edecode(str) {
        var c1, c2, c3, c4;
        var i, len, out;
        var base64DecodeChars = new Array(
            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
            52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
            -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
            15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
            -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
            41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1);

        len = str.length;
        i = 0;
        out = "";
        while (i < len) {
            /* c1 */
            do {
                c1 = base64DecodeChars[str.charCodeAt(i++) & 0xff];
            } while (i < len && c1 == -1);
            if (c1 == -1)
                break;

            /* c2 */
            do {
                c2 = base64DecodeChars[str.charCodeAt(i++) & 0xff];
            } while (i < len && c2 == -1);
            if (c2 == -1)
                break;

            out += String.fromCharCode((c1 << 2) | ((c2 & 0x30) >> 4));

            /* c3 */
            do {
                c3 = str.charCodeAt(i++) & 0xff;
                if (c3 == 61)
                    return out;
                c3 = base64DecodeChars[c3];
            } while (i < len && c3 == -1);
            if (c3 == -1)
                break;

            out += String.fromCharCode(((c2 & 0XF) << 4) | ((c3 & 0x3C) >> 2));

            /* c4 */
            do {
                c4 = str.charCodeAt(i++) & 0xff;
                if (c4 == 61)
                    return out;
                c4 = base64DecodeChars[c4];
            } while (i < len && c4 == -1);
            if (c4 == -1)
                break;
            out += String.fromCharCode(((c3 & 0x03) << 6) | c4);
        }
        return out;
    }


    /***************************************************
     * 
     ***************************************************/
    public static print_baseui_code(bui: BaseUI) {
        console.log("############################ " + cc.js.getClassName(bui));
        let get_file_dir = (n: cc.Node, path: string = null) => {
            if (n == bui.node) {
                return path;
            } else {
                return get_file_dir(n.parent, n.name + (path == null ? "" : "/" + path));
            }
        }

        let text = "";

        let all_label = bui.node.getComponentsInChildren(cc.Label);
        for (let i = 0; i < all_label.length; i++) {
            let c = all_label[i];
            if (c.node.name == "New Label") continue;
            let path = get_file_dir(c.node);
            text += `this.SetLabel("${path}" , "");\n`;
        }
        
        console.log(text);
        
        //////////////////////////// QUICKLIST
        let all_quicklist: QuickList[] = bui.node.getComponentsInChildren(QuickList);
        for (let i = 0; i < all_quicklist.length; i++) {
            let c = all_quicklist[i];
            let path = get_file_dir(c.node);
            console.log(`
            init_quicklist_${i + 1}(ds:any): void {
                let list: QuickList = this.GetGameComponent("${path}", QuickList)
                list.init<any>({
                    data: ds,
                    init: function (item: QuickList_item, data, i: number): void {
                        
                    },
                    button_click: function (item: QuickList_item, data, onBtn_name: string, target: cc.Button, i: number): number | void {
                        switch (onBtn_name) {
                            case "":
                                break;
                            default:
                                break;
                        }
                    }
                });
            }
                `);
        }
    }
}
